home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / RAMDisk 1.2 / Read Me < prev    next >
Encoding:
Text File  |  1995-07-19  |  7.8 KB  |  181 lines  |  [TEXT/ttxt]

  1. DTS sample RAM disk.  Originally by Gordon Sheridan.  Updated by Jim Luther.
  2. Metrowerks conversion by Brian Bechtel, DTS 940519 at the WWDC (Thanks to
  3. the Metrowerks coding lab.)  1.2 update on vacation in Kauai, which says
  4. something about me which I'd really not rather examine right now...
  5.  
  6. This sample is a control panel, which installs a RAM disk. Under Metrowerks
  7. and Symantec, this sample is completely in C.
  8.  
  9. How I converted this program from MPW to Metrowerks.
  10.  
  11. • Added a main() routine to the driver to handle Metrowerks' startup code.
  12. • Cleaned up various errors or warnings where Metrowerks was tighter than 
  13.   MPW or Symantec.
  14. • Created a project file for the control panel.  This project creates a
  15.   code resource of type cdev, id -4064, which is a control panel.  This
  16.   project file is '3RamCDEV.µ'.
  17. • I built the resource file, and named it '3RamCDEV.µ.rsrc'.  This ensures
  18.   that the resources will be automatically included when you build the
  19.   control panel.
  20. • Created a project file for the DRVR.  This project is a code resource
  21.   of type DRVR, id 48, which is the driver itself.  Set the project so
  22.   that the DRVR resource is merged into '3RamCDEV.µ.rsrc'.
  23. • Created a project file for the INIT.  This project is a code resource
  24.   of type INIT, id 0, which will install the driver.  Set the project so
  25.   that the INIT resource is merged into '3RamCDEV.µ.rsrc'.
  26. • I had to change the code slightly, because this driver was using some
  27.   low memory globals directly.  I now handle low memory accesses by using
  28.   accessor functions.  There was one problem; UnitNTryCnt was not defined.
  29.   I created my own accessor functions for this low memory global.  This is
  30.   fixed in the Universal Headers starting with ETO 15.
  31. • Recalculate BufPtr from the low memory global.
  32.  
  33. There is no way to set the driver flags in the driver header.  You have
  34. to either use ResEdit to change them to the desired values, or set them
  35. explicitly in the driver.  This sample driver sets the flags directly,
  36. in the DRVROpen() routine.
  37.  
  38. Build Order
  39.  
  40. The control panel consists of four parts: various resources needed to
  41. run, plus an 'INIT' to load the driver, a 'DRVR' which is the driver
  42. itself, and a 'cdev' which is the user interface for setting up the
  43. driver.
  44.  
  45. If you are using the .r file, use MPW or SARez to build the resource
  46. file RamCDev.µ.rsrc.  All three projects assume the existence of
  47. 3RamCDev.µ.rsrc
  48.  
  49. Build the project 1RamINIT.µ.  This will add an 'INIT' resource to
  50. 3RamCDev.µ.rsrc.
  51.  
  52. Build the project 2RamDRVR.µ.  This will add a 'DRVR' resource to
  53. 3RamCDev.µ.rsrc.
  54.  
  55. Build the project 3RamCDEV.µ.  This will create a control panel
  56. containing the 'INIT', 'DRVR', and 'cdev' resources necessary to run
  57. this control panel.
  58.  
  59. You can use the AppleScript provided to build either the Metrowerks or
  60. Symantec versions of this RAMDisk.
  61.  
  62. Known errors in Metrowerks:
  63.  
  64. MW C/C++ 68K 1.0 & earlier: The driver name ".RamDRVR" is put into the
  65. driver as {09}{00}.RamDRVR.  I had to change this to {08}.RamDRVR{00}
  66. to be correct.  This is what it should have generated.  Use ResEdit.
  67. This is fixed in MW C/C++ 68K 1.0.1.
  68.  
  69. Version History:
  70.  
  71. 1.0 First release
  72.  
  73. 1.1 In the file RAMInit.c, in the procedure GrowUnitTable(), there was
  74. a line which read:
  75.  newUnitTableBase = NewPtrSysClear(sizeof(newUnitEntryCount * sizeof(long)));
  76. this line should be
  77.  newUnitTableBase = NewPtrSysClear(newUnitEntryCount * sizeof(long));
  78. Because of this bug, trying to grow the unit table will overwrite other
  79. parts of the system heap and potentially crash.  Thanks to Mike Wiese
  80. for finding this bug.
  81.  
  82. 1.2 Fixed several issues in RAMInit.c:
  83.  
  84. • DriverInstall (suggested by John Wang)
  85. Instead of creating a AuxDCE record, we were creating a DCtlEntry.
  86. Because the record is smaller, the dCtlSlot field is garbage and causes
  87. _SUpdateSrt to be called when the driver is closed.
  88.  
  89. • DriverRemove (suggested by Mike Wiese)
  90. DriverRemove should not be disposing the driverhandle stored in
  91. dCltDriver, since the install routine calls ReleaseResource or
  92. DisposHandle as appropriate. Plus, if it's pointer based as it should
  93. be, disposeHandle won't work.
  94.  
  95. • DriverInstall (suggested by François Grieu)
  96. The Sample RAMDisk is installed with the dRamBased bit set.  Therefore,
  97. calls to this driver cause the DCtlEntry to be passed to _RecoverHandle
  98. and _HLock, and the driver's code Handle to _HLock.  Doing this is
  99. illegal at interrupt time, because the Memory Manager is not reentrant.
  100.  Most noticeably, a foreground app relying on MemError() stands a risk
  101. to miss errors when the shared RAMdisk is remotely accessed, or if a
  102. sound is playing from a file on the RAMdisk (using SndStartFilePlay),
  103. because each access to the RAMdisk clears the global MemErr.
  104.  
  105. By contrast, physical disks (and AppleShare) drivers are installed with
  106. the dRamBased bit clear, which makes them immune to this particular
  107. problem.
  108.  
  109. The solution is to modify how the driver is installed : clear the
  110. dRamBased bit in the dCtlFlags field of the DCtlEntry, and change the
  111. dCtlDriver field from a Handle to a Pointer; also the DCtlEntry must be
  112. locked.  I tried this for using a debugger and is fixes the problem. 
  113. As an aside benchmarks of the emulated disk are noticeably improved.
  114.  
  115. • DriverInstall
  116. DriverInstall changed to myDriverInstall.  Universal Headers 2.0 now
  117. contains a definition for DriverInstall, and we don't want to create
  118. confusion in naming.
  119.  
  120. • DriverRemove
  121. DriverRemove changed to myDriverRemove.  Universal Headers 2.0 now
  122. contains a definition for DriverRemove, and we don't want to create
  123. confusion in naming.
  124.  
  125. • GetUnusedDrvrRefNum (suggested by Matthew E. Axsom)
  126. The problem occurs in the following lines of code:
  127.  
  128. > while ((unitTable[unitNumber] != nil) && (unitNumber < unitEntryCount)) 
  129. >  ++unitNumber;
  130. >
  131. > if (unitTable[unitNumber] == nil)       /* Find an empty entry? */ 
  132. >  /* Yes, then calculate its driver reference number */ 
  133. >  drvrRefNum = -1 * (unitNumber +1);
  134.  
  135. The above code works just fine as long as the unit table has at least 1
  136. empty slot in it.  If the unit table is completely full, i.e., no empty
  137. slots then this section of code can produce an invalid drvrRefNum.  I
  138. believe that if the table is full that the routine should return 0
  139. (zero) and then grow the unit table and try again.  Instead, here's
  140. what can happen if the unit table is completely full:
  141.  
  142. If there are no empty slots in the unit table then eventually unitNumber
  143. will be >= unitEntryCount and the 'while' loop will terminate with
  144. unitNumber equal to unitEntryCount.  Since there are only
  145. unitEntryCount-1 entries in the unit table, unitNumber now contains an
  146. "out of bounds" index for the unit table. After falling out of the
  147. 'while' loop, the 'if' statement then uses the "out of bounds"
  148. unitNumber for indexing into unitTable.  At this point if the address
  149. pointed to by unitTable[unitNumber] is nil then we get a "valid"
  150. drvrRefNum which is really invalid because unitNumber is "out of
  151. bounds".  What should happen is that the table is full and a drvrRefNum
  152. of 0 (zero) be returned so the unit table can be grown.
  153.  
  154. Since I needed to load a driver, I corrected the code this way:
  155.  
  156. > while (unitNumber < unitEntryCount) {
  157. >  if (unitTable[unitNumber] == nil) { /* Find an empty entry? */ 
  158. >     /* Yes, then calculate its driver reference number */ 
  159. >     drvrRefNum = -1 * (unitNumber +1);
  160. >     break;
  161. >  }
  162. >  else
  163. >     ++unitNumber;
  164. > }
  165.  
  166. I tested this out and, as far as I can tell, it works.  It correctly
  167. detects a full unit table and returns 0.  The calling routine then
  168. grows the unit table and tries again, this time with success.
  169.  
  170. • GetUnitEntryCount
  171. Changed to use new definition in Universal Headers 2.0.
  172.  
  173. • SetUnitEntryCount
  174. Changed to use new definition in Universal Headers 2.0.
  175.  
  176. • All three Metrowerks Projects
  177. I added the keyword STR# resource from "Toasty's Keyword Resources",
  178. which can be found on the Internet at sumex-aim.stanford.edu and 
  179. various other online services. This new STR# gives highlighting to 
  180. all Apple defined keywords.  (Default is green)
  181.